package com.xiaopeng.common.secure;

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.BeanProperty;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.ser.ContextualSerializer;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import java.io.IOException;
import java.util.Objects;

/**
 * 脱敏序列化
 * 对原字段进行脱敏，并对原值进行加密后设置到新字段（前端需要要查看原数据时 传递给后端由后端解密返回）
 * @author xiaopeng
 */
@Slf4j
public class DesensitizationEncryptSerialize extends JsonSerializer<String> implements ContextualSerializer {


    private Desensitization desensitization;
    public DesensitizationEncryptSerialize() {
    }

    public DesensitizationEncryptSerialize(Desensitization desensitization) {
        this.desensitization = desensitization;
    }

    /**
     * 选择对应的序列化
     *
     * @return
     * @throws JsonMappingException
     */
    @Override
    public JsonSerializer<?> createContextual(SerializerProvider prov, BeanProperty property) throws JsonMappingException {
        Desensitization desensitization = property.getAnnotation(Desensitization.class);
        if (Objects.nonNull(desensitization)) {
            // 直接返回this desensitization会给覆盖
            return new DesensitizationEncryptSerialize(desensitization);
        }
        return prov.findValueSerializer(property.getType(), property);
    }

    /**
     * 序列化处理
     */
    @Override
    public void serialize(String value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
        String desensitizationTest = null;
        try {
            // 原字段进行脱敏处理
            desensitizationTest = DesensitizedUtils.desensitized(value, this.desensitization.value());
            gen.writeObject(desensitizationTest);
            // 对原数据进行加密并传递给前端，前端需要要查看原数据时 传递给后端由后端解密返回
            String fieldName = gen.getOutputContext().getCurrentName();
            // 获取配置
            DesensitizationProperties properties = DesensitizationProperties.INSTANCE;
            String encryptFieldName = fieldName + properties.getEncryptFieldSuffix();
            // 对原值进行加密 并设置到新字段
            gen.writeStringField(encryptFieldName, CryptoUtils.rsaEncrypt(value, properties.getPublicKey()));
        } catch (Exception e) {
            log.error("Json转换-字段脱敏异常 原值：{} 异常原因：{}", value, e.getMessage(), e);
            if (StringUtils.isEmpty(desensitizationTest)) {
                gen.writeObject("***");
            }
        }
    }
}
